import java.io.Serializable;
import java.util.Vector;

import javax.sound.midi.Instrument;


public class Melody implements Serializable{

	private static final long serialVersionUID = 9177966239470423739L;
	private Vector<Vector<Note>> melody;
	private int beatPerMinute = Constant.DEFAULT_TEMPO;
	private int instrumentIndex;
	
	public Melody()
	{
		melody = new Vector<Vector<Note>>();
	}
	
	public Melody(int nbBeats)
	{
		melody = new Vector<Vector<Note>>(nbBeats);
		for (int i = 0; i < nbBeats; i++) {
			melody.add(new Vector<Note>());
		}
	}
	
	public void add(int position, Note note)
	{
		Vector<Note> vector = melody.get(position);
		vector.add(note);
	}
	
	public void add(int position, int pitch)
	{
		boolean found = false;
		Vector<Note> notes;
		
		int startIndex = position - (Note.MAX_DURATION - 1);
		if (startIndex < 0) {
			startIndex = 0;
		}
		
		for (int i = startIndex; i <= position; i++)
		{
			notes = melody.get(i);
			
			for (Note note : notes) {
				if (note.getPitch() == pitch && note.getDuration()+i >= position+1)
				{
					found = true;
					if (this.size() == ((int)note.getDuration() + position)) {
						note.resetDuration();
					} else {
						note.increaseDuration();
					}
					break;
				}
			}
		}
		if (!found)
		{
			melody.get(position).add(new Note(pitch));
		}
	}
	
	public void remove(int position, int pitch)
	{
		Vector<Note> notes;
		for (int i = position-(Note.MAX_DURATION-1); i <= position; i++)
		{
			notes = melody.get(i);
			for (int j=0; j < notes.size(); j++) {
				if (notes.get(j).getPitch() == pitch && notes.get(j).getDuration()+i >= position)
				{
					notes.removeElementAt(j);
					break;
				}
			}
		}
	}
	
	public Vector<Note> get(int position)
	{
		return melody.get(position);
	}
	
	public int size()
	{
		return melody.size();
	}
	
	public void resize(int nbBeats)
	{
		if (nbBeats < melody.size())
		{
			for (int i = nbBeats; i < melody.size(); i++) {
				melody.removeElementAt(i);
			}
			// reduce the duration of the note too long for the new duration
			for (int i = (melody.size() - Note.MAX_DURATION); i < melody.size(); ++i) {
				int durationLimit = melody.size() - i;
				for (Note note : melody.get(i)) {
					if ((int)note.getDuration() > durationLimit) {
						note.resetDuration(durationLimit);
					}
				}
			}
		}
		else
		{
			for (int i = melody.size(); i < nbBeats; i++) {
				melody.add(i, new Vector<Note>());
			}
		}
	}
	
	public void setBeatPerMinute(int beatPerMinute) {
		this.beatPerMinute = beatPerMinute;
	}
	
	public int getBeatPerMinute() {
		return this.beatPerMinute;
	}
	
	public void setInstrumentIndex(int instrumentIndex) {
		this.instrumentIndex = instrumentIndex;
	}
	
	public int getInstrumentIndex() {
		return this.instrumentIndex;
	}
}
